package org.batatasframework.expression;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.batatasframework.properties.PropertiesName;
import org.batatasframework.values.StringValueGetter;
import org.batatasframework.values.ValueGetter;

/**
 * <pre>
 * 表达式
 * 如：
 * name = -f my -m 100 或 place = one,two... 等
 * 
 * 这里是一个表达式的语句，不一定是指令；
 * 解析后对应：
 * {@link #name} = name
 * {@link #value} = -f my -m 100
 * </pre>
 * 
 * <pre>
 * 所有一行的定义都应该是表达式，但如果没有出现"="号的情况，该字符串可能是名字，也可能是值。
 * 如：
 * 在定义上，"name=XXX"；其中的name可以忽略，直接写成"XXX"，这个时候，则表示值；
 * 如果"A2=[XXX]"或"A2="的表达式中，如果只出现"A2"，则应该认为是名称的定义
 * 
 * 为了方便和完整，不允许不出现"="号的情况
 * </pre>
 * 
 * <pre>
 * 复杂的情况：
 * 如果出现：
 * name[...] = ...
 * name = ...
 * 这种情况，应该如何处理？自动调换？
 * 
 * name = ...
 * name = ...
 * name.option[...] = ...
 * name.option[...] = ...
 * name.option[...] = ...
 * </pre>
 * @author jackson
 *
 */
public class ExpressionClause extends ExpressionValue{
	public static final ExpressionClause NULL = new ExpressionClause();
	
	private final Named name;
	private Map<String, ValueGetter> extraValues;
	private Map<Named, ExpressionValue> subClauses;
	
	private ExpressionClause(){
		this.name  = Named.NULL_VALUE;
	}

	protected ExpressionClause(Named name, String extra, String value) throws Exception{
		super(extra, value);
		this.name = name;
	}
	
	public ExpressionClause(String name, String extra, String value) throws Exception{
		this(new Named(name), extra, value);
	}

	public ExpressionClause(PropertiesName name, String value) throws Exception{
		this(name.getName(), name.getArgument(), value);
	}

	/**
	 * <pre>
	 * 这里合并的是以下的情况：
	 * name = ...
	 * name[...1] = ...
	 * name[...2] = ...
	 * name[...3] = ...
	 * name[...4] = ...
	 * 
	 * 合并后的扩展字段{@link #extraValues}的key为"...1"等内容；
	 * 这个内容也可以用于解析成一定的方式
	 * </pre>
	 */
	public boolean parse(PropertiesName name, String value) {
		if(this.name.equals(name)){
			if(name.hasArgument()){
				if(extraValues == null) extraValues = new HashMap<>();
				extraValues.put(name.getArgument(), StringValueGetter.valueOf(value));
				return true;
			}
		}
		return false;
	}

	public void addChild(ExpressionClause child){
		if(null == subClauses) subClauses = new HashMap<>();
		subClauses.put(child.name, child);
	}
	
	public Set<Entry<String, ValueGetter>> extrasSet(){
		if(null != extraValues) return extraValues.entrySet();
		return Collections.emptySet();
	}
	
	public ValueGetter getExtra(String name){
		if(null == extraValues) return null;
		return extraValues.get(name);
	}
	
	public ExpressionValue getSub(String name){
		if(null == subClauses) return null;

		return subClauses.get(Named.valueOf(name));
		//return subClauses.get(this.name.concat(name));
	}
	
	public Named getName() {
		return name;
	}

	@Override
	public String toString() {
		return name.toString();
	}
	
	public boolean is(Object name){
		return this.name.equals(name);
	}
	
	/** 是不是name.name.name这种格式 */
	public boolean associated(){
		return name.associated();
	}
	
}
